/// <summary>
//                                                                      //
//  Developer   : Wicus Botha                                           //
//                                                                      //
//  Description :                                                       //
//                                                                      //
//  History     : WB - 2008-10-20 - Created                             //
//                                                                      //
/// </summary>

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Reflection;
using log4net;

namespace IQ.DbBase
{

    [AttributeUsage(AttributeTargets.Property)]
    public class DbFieldAttribute : Attribute
    {
        #region # Constructor #
        public DbFieldAttribute(string fieldName)
        {
            this.fieldname = fieldName;
        }
        #endregion

        #region - Private variables -
        private string fieldname;
        #endregion

        #region - Public methods -
        public string FieldName
        {
            get { return this.fieldname; }
        }
        #endregion
    }

    public static class DbReflection
    {
    }

    public static class PropertyLoader
    {
        private static readonly log4net.ILog Logging = LogManager.GetLogger("IQ.DbReflection.PropertyLoader");
        
        #region - Public methods -

        public static void InitializeProperties(object objToInit)
        {
            PropertyInfo[] propList = objToInit.GetType().GetProperties();
            foreach (PropertyInfo property in propList)
            {
                try
                {
                    property.SetValue(objToInit, null, null);
                }
                catch (Exception e)
                {
                   Logging.Error("InitializeProperties = " + e.Message);
                }                
            }
        }
        public static void LoadDataIntoProperties(object objToLoad, IDataRecord dr)
        {
            if (dr != null)
            {
                PropertyInfo[] propList = objToLoad.GetType().GetProperties();
                int fieldIndex = -1;
                foreach (PropertyInfo property in propList)
                {
                    try
                    {
                        fieldIndex = dr.GetOrdinal(property.Name);
                    }
                    catch (Exception)
                    {
                        try
                        {
                            //if (Attribute.IsDefined(property, typeof(DBFieldAttribute)))
                            DbFieldAttribute attribute = (DbFieldAttribute)Attribute.GetCustomAttribute(property, typeof(DbFieldAttribute));
                            fieldIndex = dr.GetOrdinal(attribute.FieldName);
                        }
                        catch (Exception)
                        {
                            fieldIndex = -1;
                        }
                    }
                    //
                    if (fieldIndex != -1)
                    {
                        if (dr[fieldIndex] == DBNull.Value)
                        {
                            try
                            {
                                property.SetValue(objToLoad, null, null);
                            }
                            catch (Exception e)
                            {
                                Logging.Error(objToLoad.ToString() + "=Set Property value error " + e.Message);
                            }
                        }
                        else
                        {
                            try
                            {
                                property.SetValue(objToLoad, dr[fieldIndex], null);
                            }
                            catch (Exception e)
                            {
                                Logging.Error(objToLoad.ToString() + "=Set Property value error " + e.Message);
                            }
                        } // end else DBNull
                    } // end fieldIndex
                } // end foreach loop
            } // end dr != null			
        }
        public static void LoadDataIntoProperties(object objToLoad, DataRow dr)
        {
            if (dr != null)
            {
                PropertyInfo[] propList = objToLoad.GetType().GetProperties();
                int fieldIndex = -1;
                foreach (PropertyInfo property in propList)
                {
                    try
                    {
                        fieldIndex = dr.Table.Columns.IndexOf(property.Name);
                    }
                    catch (Exception)
                    {
                        try
                        {
                            //if (Attribute.IsDefined(property, typeof(DBFieldAttribute)))
                            DbFieldAttribute attribute = (DbFieldAttribute)Attribute.GetCustomAttribute(property, typeof(DbFieldAttribute));
                            fieldIndex = dr.Table.Columns.IndexOf(attribute.FieldName);
                        }
                        catch (Exception)
                        {
                            fieldIndex = -1;
                        }
                    }
                    //
                    if (fieldIndex != -1)
                    {
                        if (dr[fieldIndex] == DBNull.Value)
                        {
                            try
                            {
                                property.SetValue(objToLoad, null, null);
                            }
                            catch (Exception e)
                            {
                                Logging.Error(objToLoad.ToString() + "=Set Property value error " + e.Message);
                            }
                        }
                        else
                        {
                            try
                            {
                                property.SetValue(objToLoad, dr[fieldIndex], null);
                            }
                            catch (Exception e)
                            {
                                Logging.Error(objToLoad.ToString() + "=Set Property value error " + e.Message);
                            }
                        } // end else DBNull
                    } // end fieldIndex
                } // end foreach loop
            } // end dr != null			
        }
        public static object GetValueForPropertyType(string value, string type)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            else
            {
                switch (type)
                {
                    case "System.String": return value.ToString();
                    case "System.Boolean": return Convert.ToBoolean(value);
                    case "System.Byte": return Convert.ToByte(value);
                    case "System.Int16": return Convert.ToInt16(value);
                    case "System.Int32": return Convert.ToInt32(value);
                    case "System.Int64": return Convert.ToInt64(value);
                    case "System.Decimal": return Convert.ToDecimal(value);
                    case "System.Single": return Convert.ToSingle(value);
                    case "System.Double": return Convert.ToDouble(value);
                    //case "System.DateTime?": // Nullable, no need, we check the value at the beginning.
                    case "System.DateTime": return Convert.ToDateTime(value);
                    default: return value.ToString();
                }
            }
        }
        public static void LoadObjectFromSnapShot(object objToLoad, string objSnapShot)
        {
            if (objToLoad != null)
            {
                PropertyInfo[] propList = objToLoad.GetType().GetProperties();
                if (String.IsNullOrEmpty(objSnapShot))
                    objSnapShot = propList[0].GetValue(objToLoad, null).ToString();
                if (!String.IsNullOrEmpty(objSnapShot))
                {
                    string[] values = objSnapShot.Split(DbConstants.FieldDelimiter);
                    for (int i = 0; i < values.Length; ++i)
                    {
                        PropertyInfo property = propList[i + 1];
                        string propertyType = (Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType).ToString();
                        // To cater for nullable properties
                        /*
                        string propertyType = (Nullable.GetUnderlyingType(property.PropertyType) != null) ? 
                            Nullable.GetUnderlyingType(property.PropertyType).ToString() + "?" :
                            property.PropertyType.ToString();
                         */
                        try
                        {
                            property.SetValue(objToLoad, GetValueForPropertyType(values[i], propertyType), null);
                        }
                        catch (Exception e)
                        {
                            Logging.Error(objToLoad.ToString() + "=Set Property value error " + e.Message);
                        }
                    }
                }
            }
        }
        public static void LoadObjectFromSnapShot(object objToLoad)
        {
            PropertyLoader.LoadObjectFromSnapShot(objToLoad, "");
        }

        public static void LoadOjectList(object[] obj, DataTable dt)
        {
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                PropertyLoader.LoadDataIntoProperties(obj[i], dt.Rows[i]);
            }
        }
        public static void LoadOjectList(object[] obj, DbDataReader dr)
        {// Not needed	
            if (dr != null && dr.HasRows)
            {
                int i = 0;
                while (dr.NextResult())
                {
                    PropertyLoader.LoadDataIntoProperties(obj[i], dr);
                    i++;
                }
            }
            if (dr != null)
                dr.Close();
        }  
        
        /* The DbDataReader with Reflection is slower than using a DataTable */

        public static void DataLoadObject(string sql, object obj)
        {
            DataTable dt = DbHelper.Load_Table(sql);
            if (dt.Rows.Count > 0)
                PropertyLoader.LoadDataIntoProperties(obj, dt.Rows[0]);
        }

        /* The DbDataReader with Reflection is slower than using a DataTable */ 
        /*
		public static void DataLoadObject(string sql, object obj) 
		{			
			DbDataReader dr = DbHelper.load_Reader(sql);			
			if (dr != null && dr.HasRows)
			{
				dr.Read();				
				PropertyLoader.LoadDataIntoProperties(obj, dr);
			}
			if (dr != null)
				dr.Close();
		}
	    */
		public static void DataLoadXml(string xml, object obj) 
		{
			DataTable dt = DbHelper.Load_TableXml(xml);
			if (dt.Rows.Count > 0)
				PropertyLoader.LoadDataIntoProperties(obj, dt.Rows[0]);
		}		
        #endregion
    }	
}
